﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;
using System.IO;
using System.Security;
using AutocompleteDemo.WebServices.AutocompleteDemo;
using System.ServiceModel.Activation;
using System.Web;
using Microsoft.SharePoint.Administration.AccessControl;

namespace AutocompleteDemo
{
    [System.Runtime.InteropServices.Guid("0B42E5CF-B5BC-438C-997F-996E61CE572A")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public sealed class AutoCompletionServiceApplication : SPIisWebServiceApplication, IFormattable, IYouCompleteMeService
    {
        private AutoCompletionServiceInstance m_serviceInstance;

        [Persisted]
        Dictionary<string, object> m_settings;

        #region Constructors
        
        public AutoCompletionServiceApplication()
        {
            this.m_settings = new Dictionary<string, object>(StringComparer.CurrentCultureIgnoreCase);
        }

        internal AutoCompletionServiceApplication(string name, AutoCompletionService service)
            : base(name, service)
        {
            this.m_settings = new Dictionary<string, object>(StringComparer.CurrentCultureIgnoreCase);
        }

        internal AutoCompletionServiceApplication(string name, AutoCompletionService service, 
            SPIisWebServiceApplicationPool applicationPool) : base(name, service, applicationPool)
        {
            this.m_settings = new Dictionary<string, object>(StringComparer.CurrentCultureIgnoreCase);
        }

        #endregion

        public override SPAdministrationLink ManageLink
        {
            get
            {
                string linkWithQuerystring = 
                    string.Concat("/_admin/AutocompleteDemo/ServiceManage.aspx?appid=",
                    this.Id.ToString());
                return new SPAdministrationLink(linkWithQuerystring);
            }
        }

        protected override string InstallPath
        {
            get
            {
                return Path.GetFullPath(SPUtility.GetGenericSetupPath(@"WebServices\AutocompleteDemo"));
            }
        }

        protected override string VirtualPath
        {
            get
            {
                return "YouCompleteMeService.svc";
            }
        }

        public Dictionary<string, object> Settings
        {
            get { return m_settings; }
        }

        public void SetValue(string settingName, object value, bool shouldUpdate)
        {
            this.m_settings[settingName] = value;
            if (shouldUpdate)
            {
                this.Update();
            }
        }

        #region Service application provisioning

        public override void Provision()
        {
            base.Provision();

            AutoCompletionServiceInstance inst = 
                new AutoCompletionServiceInstance(SPServer.Local, this.Service as AutoCompletionService);
            inst.Name = string.Concat("instance_", this.Id.ToString());
            inst.Update();
            inst.Provision();

            this.GrantDefaultServiceAccess();
            this.Update();
        }

        public override void Unprovision(bool deleteData)
        {
            base.Status = SPObjectStatus.Unprovisioning;
            this.Update();
            base.Unprovision(deleteData);
            base.Status = SPObjectStatus.Disabled;
            this.Update();
        }

        #endregion

        #region IFormattable

        public string ToString(string format, IFormatProvider formatProvider)
        {
            return string.Format(format, "AutoCompletion Service Application", formatProvider);
        }

        #endregion

        public Uri DefaultServicePath
        {
            get { return this.DefaultEndpoint.GetEndpointUri(this.OnlineInstance); }
        }

        public AutoCompletionServiceInstance OnlineInstance
        {
            get
            {
                if (null == m_serviceInstance)
                {
                    foreach (SPServiceInstance i in this.ServiceInstances)
                    {
                        AutoCompletionServiceInstance instance = i as AutoCompletionServiceInstance;
                        if ((instance != null) && instance.IsOnline)
                        {
                            m_serviceInstance = instance;
                            break;
                        }
                    }
                }

                return m_serviceInstance;
            }
        }

        internal void DemandAdministrationReadAccess()
        {
            this.DemandAdministrationAccess(SPCentralAdministrationRights.Read);
        }

        internal void RegisterAsDefaultApplication()
        {
            AutoCompletionServiceApplicationProxy proxyForApplicationName = 
                GetProxyForApplicationName(base.Name);
            if (proxyForApplicationName != null)
            {
                SPServiceApplicationProxyGroup group = SPServiceApplicationProxyGroup.Default;
                group.Add(proxyForApplicationName);
                group.Update(true);
            }
            else
            {
                throw new ApplicationException("Failed to register as default service application.");
            }
        }

        internal static AutoCompletionServiceApplication GetLocalApplicationByName(string name)
        {
            return AutoCompletionService.Local.GetWebApplicationByName(name);
        }

        internal static AutoCompletionServiceApplicationProxy GetProxyForApplicationName(string applicationName)
        {
            string proxyNameForApplicationName = GetProxyNameForApplicationName(applicationName);

            if (!string.IsNullOrEmpty(proxyNameForApplicationName))
            {
                AutoCompletionServiceProxy proxy = SPFarm.Local.ServiceProxies.GetValue<AutoCompletionServiceProxy>();
                if (proxy != null)
                {
                    AutoCompletionServiceApplicationProxy proxy2 =
                        proxy.ApplicationProxies.GetValue<AutoCompletionServiceApplicationProxy>(proxyNameForApplicationName);
                    if (proxy2 != null)
                    {
                        return proxy2;
                    }
                }
            }
            
            return null;
        }

        internal static string GetProxyNameForApplicationName(string applicationName)
        {
            foreach (AutoCompletionServiceApplicationProxy proxy2 in SPFarm.Local.ServiceProxies.GetValue<AutoCompletionServiceProxy>().ApplicationProxies)
            {
                if (proxy2.AutoCompletionApplication.Name == applicationName)
                {
                    return proxy2.Name;
                }
            }

            return string.Empty;
        }


        #region Powershell Support

        internal void CloneValues(System.Collections.Specialized.HybridDictionary incomingValues)
        {
            // Add initialization prooperties as needed
            this.CopyValue(incomingValues, "SomeProperty", "SomeProperty");
        }

        private void CopyValue(System.Collections.Specialized.HybridDictionary incomingValues, string powerShellName, string applicationName)
        {
            if (incomingValues[powerShellName] != null)
            {
                this.SetValue(applicationName, incomingValues[powerShellName], false);
            }
        }

        internal void CommitChanges()
        {
            this.Update();
        }

        #endregion

        #region AutoCompletion services

        public string[] GetStates(string prefixText, int count)
        {
            if (count == 0)
                count = 10;

            CitiesHelper helper = CitiesHelper.GetHelper();

            return helper.GetStates(prefixText, count);
        }

        public string[] GetCitiesForState(string prefixText, int count, string contextKey)
        {
            if (count == 0)
                count = 10;

            CitiesHelper helper = CitiesHelper.GetHelper();

            return helper.GetCitiesForState(prefixText, count, contextKey);
        }

        #endregion
    }
}
